package com.gitee.wsl.transform.encode.sample

import com.gitee.wsl.ext.base.DASHED
import com.gitee.wsl.ext.base.DOT
import com.gitee.wsl.ext.base.SLASH
import com.gitee.wsl.ext.bitcode.toBinaryString
import com.gitee.wsl.ext.string.appendCodePoint
import com.gitee.wsl.ext.string.codePointAt
import com.gitee.wsl.ext.string.codePointCount
import com.gitee.wsl.ext.string.containsOnly
import kotlin.jvm.JvmOverloads


/**
 * 莫尔斯电码的编码和解码实现<br></br>
 * 参考：https://github.com/TakWolf-Deprecated/Java-MorseCoder
 *
 * @author looly, TakWolf
 * @since 4.4.1
 */
class Morse @JvmOverloads constructor(
// short mark or dot
    private val dit: Char = Char.DOT, // longer mark or dash
    private val dah: Char = Char.DASHED,
    private val split: Char = Char.SLASH,
) {
    /**
     * 构造
     *
     * @param dit 点表示的字符
     * @param dah 横线表示的字符
     * @param split 分隔符
     */


    /**
     * 编码
     *
     * @param text 文本
     * @return 密文
     */
    fun encode(text: String): String {
        var text = text
        //Assert.notNull(text, "Text should not be null.")

        text = text.uppercase()
        val morseBuilder = StringBuilder()
        val len: Int = text.codePointCount(0, text.length)
        for (i in 0..<len) {
            val codePoint: Int = text.codePointAt(i)
            var word = ALPHABETS[codePoint]
            if (word == null) {
                word = codePoint.toBinaryString()
            }
            morseBuilder.append(word.replace('0', dit).replace('1', dah)).append(split)
        }
        return morseBuilder.toString()
    }

    /**
     * 解码
     *
     * @param morse 莫尔斯电码
     * @return 明文
     */
    fun decode(morse: String): String {
        val dit = this.dit
        val dah = this.dah
        val split = this.split
        require(morse.containsOnly(dit, dah, split)) { "Incorrect morse." }
        val words = morse.split(split)
        val textBuilder = StringBuilder()
        var codePoint: Int?
        for (word in words) {
            var word: String = word
            if (word.isEmpty()) {
                continue
            }
            word = word.replace(dit, '0').replace(dah, '1')
            codePoint = DICTIONARIES[word]
            if (codePoint == null) {
                codePoint = word.toInt(2)
            }
            textBuilder.appendCodePoint(codePoint)
        }
        return textBuilder.toString()
    }

    companion object {
        private val ALPHABETS= HashMap<Int, String>() // code point -> morse
        private val DICTIONARIES = HashMap<String, Int>() // morse -> code point

        /**
         * 注册莫尔斯电码表
         *
         * @param abc 字母和字符
         * @param dict 二进制
         */
        private fun registerMorse(abc: Char, dict: String) {
            ALPHABETS.put(abc.code, dict)
            DICTIONARIES.put(dict, abc.code)
        }

        init {
            // Letters
            registerMorse('A', "01")
            registerMorse('B', "1000")
            registerMorse('C', "1010")
            registerMorse('D', "100")
            registerMorse('E', "0")
            registerMorse('F', "0010")
            registerMorse('G', "110")
            registerMorse('H', "0000")
            registerMorse('I', "00")
            registerMorse('J', "0111")
            registerMorse('K', "101")
            registerMorse('L', "0100")
            registerMorse('M', "11")
            registerMorse('N', "10")
            registerMorse('O', "111")
            registerMorse('P', "0110")
            registerMorse('Q', "1101")
            registerMorse('R', "010")
            registerMorse('S', "000")
            registerMorse('T', "1")
            registerMorse('U', "001")
            registerMorse('V', "0001")
            registerMorse('W', "011")
            registerMorse('X', "1001")
            registerMorse('Y', "1011")
            registerMorse('Z', "1100")
            // Numbers
            registerMorse('0', "11111")
            registerMorse('1', "01111")
            registerMorse('2', "00111")
            registerMorse('3', "00011")
            registerMorse('4', "00001")
            registerMorse('5', "00000")
            registerMorse('6', "10000")
            registerMorse('7', "11000")
            registerMorse('8', "11100")
            registerMorse('9', "11110")
            // Punctuation
            registerMorse('.', "010101")
            registerMorse(',', "110011")
            registerMorse('?', "001100")
            registerMorse('\'', "011110")
            registerMorse('!', "101011")
            registerMorse('/', "10010")
            registerMorse('(', "10110")
            registerMorse(')', "101101")
            registerMorse('&', "01000")
            registerMorse(':', "111000")
            registerMorse(';', "101010")
            registerMorse('=', "10001")
            registerMorse('+', "01010")
            registerMorse('-', "100001")
            registerMorse('_', "001101")
            registerMorse('"', "010010")
            registerMorse('$', "0001001")
            registerMorse('@', "011010")
        }
    }
}
